﻿namespace Fiddler
{
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Diagnostics;
    using System.Globalization;
    using System.IO;
    using System.Net;
    using System.Net.NetworkInformation;
    using System.Net.Sockets;
    using System.Reflection;
    using System.Text;
    using System.Threading;

    public class ServerChatter
    {
        private bool _bLeakedHeaders;
        internal bool _bWasForwarded;
        internal static int _cbServerReadBuffer = 0x8000;
        private int _iBodySeekProgress;
        private long _lngLastChunkInfoOffset;
        private long _lngLeakedOffset;
        private int iEntityBodyOffset;
        private HTTPResponseHeaders m_inHeaders;
        private PipeReadBuffer m_responseData;
        private long m_responseTotalDataCount;
        private Session m_session;
        public ServerPipe pipeServer;

        internal ServerChatter(Session oSession)
        {
            this._lngLastChunkInfoOffset = -1;
            this.m_session = oSession;
            this.m_responseData = new PipeReadBuffer(false);
        }

        internal ServerChatter(Session oSession, string sHeaders)
        {
            this._lngLastChunkInfoOffset = -1;
            this.m_session = oSession;
            this.m_inHeaders = Parser.ParseResponse(sHeaders);
        }

        private static byte[] _BuildSOCKS4ConnectHandshakeForTarget(string sTargetHost, int iPort)
        {
            MemoryStream stream = new MemoryStream();
            byte[] bytes = Encoding.ASCII.GetBytes(sTargetHost);
            stream.WriteByte(4);
            stream.WriteByte(1);
            stream.WriteByte((byte) (iPort >> 8));
            stream.WriteByte((byte) (iPort & 0xff));
            stream.WriteByte(0);
            stream.WriteByte(0);
            stream.WriteByte(0);
            stream.WriteByte(0x7f);
            stream.WriteByte(0);
            stream.Write(bytes, 0, bytes.Length);
            stream.WriteByte(0);
            return stream.ToArray();
        }

        private void _deleteInformationalMessage()
        {
            this.m_inHeaders = null;
            byte[] buffer = new byte[this.m_responseData.Length - this.iEntityBodyOffset];
            this.m_responseData.Position = this.iEntityBodyOffset;
            this.m_responseData.Read(buffer, 0, buffer.Length);
            this.m_responseData.Dispose();
            this.m_responseData = new PipeReadBuffer(buffer.Length);
            this.m_responseData.Write(buffer, 0, buffer.Length);
            this.m_responseTotalDataCount = 0;
            this.iEntityBodyOffset = this._iBodySeekProgress = 0;
        }

        internal void _detachServerPipe()
        {
            if (this.pipeServer != null)
            {
                if (((this.pipeServer.ReusePolicy != PipeReusePolicy.NoReuse) && (this.pipeServer.ReusePolicy != PipeReusePolicy.MarriedToClientPipe)) && (this.pipeServer.isClientCertAttached && !this.pipeServer.isAuthenticated))
                {
                    this.pipeServer.MarkAsAuthenticated(this.m_session.LocalProcessID);
                }
                Proxy.htServerPipePool.EnqueueOrClosePipe(this.pipeServer);
                this.pipeServer = null;
            }
        }

        internal byte[] _PeekAtBody()
        {
            if (((this.iEntityBodyOffset < 1) || (this.m_responseData == null)) || (this.m_responseData.Length < 1))
            {
                return new byte[0];
            }
            int count = ((int) this.m_responseData.Length) - this.iEntityBodyOffset;
            if (count < 1)
            {
                return new byte[0];
            }
            byte[] dst = new byte[count];
            Buffer.BlockCopy(this.m_responseData.GetBuffer(), this.iEntityBodyOffset, dst, 0, count);
            return dst;
        }

        internal void _PoisonPipe()
        {
            if (this.pipeServer != null)
            {
                this.pipeServer.ReusePolicy = PipeReusePolicy.NoReuse;
            }
        }

        private void _ReturnFileReadError(string sRemoteError, string sTrustedError)
        {
            string str;
            this.Initialize(false);
            if ((this.m_session.LocalProcessID > 0) || this.m_session.isFlagSet(SessionFlags.RequestGeneratedByFiddler))
            {
                str = sTrustedError;
            }
            else
            {
                str = sRemoteError;
            }
            str = str.PadRight(0x200, ' ');
            this.m_session.responseBodyBytes = Encoding.UTF8.GetBytes(str);
            this.m_inHeaders = new HTTPResponseHeaders(CONFIG.oHeaderEncoding);
            this.m_inHeaders.HTTPResponseCode = 0x194;
            this.m_inHeaders.HTTPResponseStatus = "404 Not Found";
            this.m_inHeaders.Add("Content-Length", this.m_session.responseBodyBytes.Length.ToString());
            this.m_inHeaders.Add("Cache-Control", "max-age=0, must-revalidate");
        }

        private Socket _SOCKSifyConnection(string sServerHostname, int iServerPort, Socket newSocket)
        {
            this._bWasForwarded = false;
            FiddlerApplication.Log.LogFormat("Creating SOCKS connection to {0}.", new object[] { this.m_session.hostname });
            bool flag = false;
            byte[] buffer = _BuildSOCKS4ConnectHandshakeForTarget(sServerHostname, iServerPort);
            newSocket.Send(buffer);
            byte[] buffer2 = new byte[0x40];
            int num = newSocket.Receive(buffer2);
            if (((num > 1) && (buffer2[0] == 0)) && (buffer2[1] == 90))
            {
                this.m_session.SetBitFlag(SessionFlags.SentToSOCKSGateway, true);
                if (num > 7)
                {
                    string str = string.Format("{0}.{1}.{2}.{3}", new object[] { buffer2[4], buffer2[5], buffer2[6], buffer2[7] });
                    this.m_session.m_hostIP = str;
                    this.m_session.oFlags["x-hostIP"] = str;
                }
                flag = true;
            }
            if (!flag)
            {
                newSocket.Close();
                newSocket = null;
                throw new InvalidDataException("SOCKS server returned failure");
            }
            return newSocket;
        }

        private bool ConnectToHost()
        {
            IPEndPoint[] pointArray = null;
            string str3;
            string str4;
            IPEndPoint[] pointArray2;
            bool flag2;
            string sHostAndPort = this.m_session.oFlags["x-overrideHost"];
            if (sHostAndPort == null)
            {
                if (this.m_session.HTTPMethodIs("CONNECT"))
                {
                    sHostAndPort = this.m_session.PathAndQuery;
                }
                else
                {
                    sHostAndPort = this.m_session.host;
                }
            }
            bool flag = false;
            if (this.m_session.oFlags["x-overrideGateway"] != null)
            {
                if (string.Equals("DIRECT", this.m_session.oFlags["x-overrideGateway"], StringComparison.OrdinalIgnoreCase))
                {
                    this.m_session.bypassGateway = true;
                }
                else
                {
                    string sAllHostAndPorts = this.m_session.oFlags["x-overrideGateway"];
                    if (sAllHostAndPorts.StartsWith("socks="))
                    {
                        flag = true;
                        sAllHostAndPorts = sAllHostAndPorts.Substring(6);
                    }
                    pointArray = Utilities.IPEndPointListFromHostPortString(sAllHostAndPorts);
                }
            }
            else if (!this.m_session.bypassGateway)
            {
                int tickCount = Environment.TickCount;
                IPEndPoint point = FiddlerApplication.oProxy.FindGatewayForOrigin(this.m_session.oRequest.headers.UriScheme, sHostAndPort);
                if (point != null)
                {
                    pointArray = new IPEndPoint[] { point };
                }
                this.m_session.Timers.GatewayDeterminationTime = Environment.TickCount - tickCount;
            }
            if (pointArray != null)
            {
                this._bWasForwarded = true;
            }
            else if (this.m_session.isFTP)
            {
                return true;
            }
            int iPort = this.m_session.isHTTPS ? 0x1bb : (this.m_session.isFTP ? 0x15 : 80);
            Utilities.CrackHostAndPort(sHostAndPort, out str3, ref iPort);
            if (pointArray != null)
            {
                if (this.m_session.isHTTPS)
                {
                    str4 = "GATEWAY:HTTPS:" + str3 + ":" + iPort.ToString();
                }
                else
                {
                    str4 = "GW:" + pointArray[0].ToString();
                }
            }
            else
            {
                str4 = (this.m_session.isHTTPS ? "HTTPS:" : "") + str3 + ":" + iPort.ToString();
            }
            if (((this.pipeServer != null) && !this.m_session.oFlags.ContainsKey("X-ServerPipe-Marriage-Trumps-All")) && !SIDsMatch(this.m_session.LocalProcessID, str4, this.pipeServer.sPoolKey))
            {
                FiddlerApplication.Log.LogFormat("Detaching server pipe. Had: {0} but needs: {1}", new object[] { this.pipeServer.sPoolKey, str4 });
                this.m_session.oFlags["X-Divorced-ServerPipe"] = string.Format("Had: {0} but needs: {1}", this.pipeServer.sPoolKey, str4);
                this._detachServerPipe();
            }
            if ((this.pipeServer == null) && !this.m_session.oFlags.ContainsKey("X-Bypass-ServerPipe-Reuse-Pool"))
            {
                this.pipeServer = Proxy.htServerPipePool.DequeuePipe(str4, this.m_session.LocalProcessID, this.m_session.id);
            }
            if (this.pipeServer != null)
            {
                StringDictionary dictionary;
                this.m_session.Timers.ServerConnected = this.pipeServer.dtConnected;
                (dictionary = this.m_session.oFlags)["x-serversocket"] = dictionary["x-serversocket"] + "REUSE " + this.pipeServer._sPipeName;
                if ((this.pipeServer.Address != null) && !this.pipeServer.isConnectedToGateway)
                {
                    this.m_session.m_hostIP = this.pipeServer.Address.ToString();
                    this.m_session.oFlags["x-hostIP"] = this.m_session.m_hostIP;
                }
                if (CONFIG.bDebugSpew)
                {
                    FiddlerApplication.DebugSpew(string.Format("Session #{0} ({1} {2}): Reusing {3}\r\n", new object[] { this.m_session.id, this.m_session.oRequest.headers.HTTPMethod, this.m_session.fullUrl, this.pipeServer.ToString() }));
                }
                return true;
            }
            if (pointArray == null)
            {
                if ((iPort < 0) || (iPort > 0xffff))
                {
                    this.m_session.oRequest.FailSession(400, "Fiddler - Bad Request", "[Fiddler] HTTP Request specified an invalid port number.");
                    return false;
                }
                try
                {
                    IPAddress[] addressArray = DNSResolver.GetIPAddressList(str3, true, this.m_session.Timers);
                    List<IPEndPoint> list = new List<IPEndPoint>();
                    foreach (IPAddress address in addressArray)
                    {
                        list.Add(new IPEndPoint(address, iPort));
                    }
                    pointArray2 = list.ToArray();
                    goto Label_04CA;
                }
                catch (Exception exception)
                {
                    this.m_session.oRequest.FailSession(0x1f6, "Fiddler - DNS Lookup Failed", string.Format("[Fiddler] DNS Lookup for \"{0}\" failed. {1}{2}", Utilities.HtmlEncode(str3), NetworkInterface.GetIsNetworkAvailable() ? string.Empty : "Windows reports that no network connection is available. \n", Utilities.DescribeException(exception)));
                    return false;
                }
            }
            pointArray2 = pointArray;
        Label_04CA:
            try
            {
                Socket newSocket = CreateConnectedSocket(pointArray2, this.m_session);
                if (flag)
                {
                    newSocket = this._SOCKSifyConnection(str3, iPort, newSocket);
                }
                if (this.m_session.isHTTPS && this._bWasForwarded)
                {
                    if (!SendHTTPCONNECTToGateway(newSocket, str3, iPort, this.m_session.oRequest.headers))
                    {
                        throw new Exception("Upstream Gateway refused requested CONNECT.");
                    }
                    this.m_session.oFlags["x-CreatedTunnel"] = "Fiddler-Created-A-CONNECT-Tunnel";
                }
                string sPoolingKey = string.Empty;
                if (this.m_session.isHTTPS)
                {
                    sPoolingKey = "HTTPS:" + str3 + ":" + iPort.ToString();
                }
                else if (this._bWasForwarded)
                {
                    sPoolingKey = "GW:" + pointArray[0].ToString();
                }
                else
                {
                    sPoolingKey = str3 + ":" + iPort.ToString();
                }
                this.pipeServer = new ServerPipe(newSocket, "ServerPipe#" + this.m_session.id.ToString(), this._bWasForwarded, sPoolingKey);
                if (flag)
                {
                    this.pipeServer.isConnectedViaSOCKS = true;
                }
                if (this.m_session.isHTTPS && !this.pipeServer.SecureExistingConnection(this.m_session, str3, this.m_session.oFlags["https-Client-Certificate"], sPoolingKey, ref this.m_session.Timers.HTTPSHandshakeTime))
                {
                    throw new Exception("Upstream Gateway refused requested CONNECT.");
                }
                flag2 = true;
            }
            catch (Exception exception2)
            {
                string str7;
                string str8;
                string str6 = string.Empty;
                SocketException exception3 = exception2 as SocketException;
                if (exception3 != null)
                {
                    if ((exception3.ErrorCode == 0x271d) || (exception3.ErrorCode == 0x2742))
                    {
                        str6 = string.Format("A Firewall may be blocking Fiddler's traffic. <br />ErrorCode: {0}.", exception3.ErrorCode);
                    }
                    else
                    {
                        str6 = string.Format("<br />ErrorCode: {0}.", exception3.ErrorCode);
                    }
                }
                if (this._bWasForwarded)
                {
                    str7 = "Fiddler - Gateway Connection Failed";
                    str8 = "[Fiddler] The socket connection to the upstream proxy/gateway failed.";
                    if (str6.Length < 0x19)
                    {
                        str6 = string.Format("Closing Fiddler, changing your system proxy settings, and restarting Fiddler may help. {0}", str6);
                    }
                }
                else
                {
                    str7 = "Fiddler - Connection Failed";
                    str8 = string.Format("[Fiddler] The socket connection to {0} failed.", Utilities.HtmlEncode(str3));
                }
                this.m_session.oRequest.FailSession(0x1f6, str7, string.Format("{0} {1} <br />{2}", str8, str6, Utilities.HtmlEncode(Utilities.DescribeException(exception2))));
                flag2 = false;
            }
            return flag2;
        }

        internal static Socket CreateConnectedSocket(IPEndPoint[] arrDest, Session _oSession)
        {
            Socket socket = null;
            bool flag = false;
            Stopwatch stopwatch = Stopwatch.StartNew();
            Exception exception = null;
            foreach (IPEndPoint point in arrDest)
            {
                try
                {
                    socket = new Socket(point.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                    socket.NoDelay = true;
                    if (FiddlerApplication.oProxy._DefaultEgressEndPoint != null)
                    {
                        socket.Bind(FiddlerApplication.oProxy._DefaultEgressEndPoint);
                    }
                    socket.Connect(point);
                    _oSession.m_hostIP = point.Address.ToString();
                    _oSession.oFlags["x-hostIP"] = _oSession.m_hostIP;
                    flag = true;
                    break;
                }
                catch (Exception exception2)
                {
                    exception = exception2;
                    if (!FiddlerApplication.Prefs.GetBoolPref("fiddler.network.dns.fallback", true))
                    {
                        break;
                    }
                    _oSession.oFlags["x-DNS-Failover"] = _oSession.oFlags["x-DNS-Failover"] + "+1";
                }
            }
            _oSession.Timers.ServerConnected = DateTime.Now;
            _oSession.Timers.TCPConnectTime = (int) stopwatch.ElapsedMilliseconds;
            if (!flag)
            {
                throw exception;
            }
            return socket;
        }

        internal void FreeResponseDataBuffer()
        {
            this.m_responseData.Dispose();
            this.m_responseData = null;
        }

        private bool GetHeaders()
        {
            if (!this.HeadersAvailable())
            {
                return false;
            }
            if (!this.ParseResponseForHeaders())
            {
                string str;
                this.m_session.SetBitFlag(SessionFlags.ProtocolViolationInResponse, true);
                this._PoisonPipe();
                if (this.m_responseData != null)
                {
                    str = "<plaintext>\n" + Utilities.ByteArrayToHexView(this.m_responseData.GetBuffer(), 0x18, (int) Math.Min(this.m_responseData.Length, 0x800));
                }
                else
                {
                    str = "{Fiddler:no data}";
                }
                this.m_session.oRequest.FailSession(500, "Fiddler - Bad Response", string.Format("[Fiddler] Response Header parsing failed.\n{0}Response Data:\n{1}", this.m_session.isFlagSet(SessionFlags.ServerPipeReused) ? "This can be caused by an illegal HTTP response earlier on this reused server socket-- for instance, a HTTP/304 response which illegally contains a body.\n" : string.Empty, str));
                return true;
            }
            if ((this.m_inHeaders.HTTPResponseCode > 0x63) && (this.m_inHeaders.HTTPResponseCode < 200))
            {
                if (this.m_inHeaders.Exists("Content-Length") && ("0" != this.m_inHeaders["Content-Length"].Trim()))
                {
                    FiddlerApplication.HandleHTTPError(this.m_session, SessionFlags.ProtocolViolationInResponse, false, true, "HTTP/1xx responses MUST NOT contain a body, but a non-zero content-length was returned.");
                }
                if ((this.m_inHeaders.HTTPResponseCode != 0x65) || !this.m_inHeaders.ExistsAndContains("Upgrade", "WebSocket"))
                {
                    if (FiddlerApplication.Prefs.GetBoolPref("fiddler.network.leakhttp1xx", true) && (this.m_session.oRequest.pipeClient != null))
                    {
                        try
                        {
                            StringDictionary dictionary;
                            this.m_session.oRequest.pipeClient.Send(this.m_inHeaders.ToByteArray(true, true));
                            (dictionary = this.m_session.oFlags)["x-fiddler-Stream1xx"] = dictionary["x-fiddler-Stream1xx"] + "Returned a HTTP/" + this.m_inHeaders.HTTPResponseCode.ToString() + " message from the server.";
                        }
                        catch (Exception exception)
                        {
                            if (FiddlerApplication.Prefs.GetBoolPref("fiddler.network.streaming.abortifclientaborts", false))
                            {
                                throw new Exception("Leaking HTTP/1xx response to client failed", exception);
                            }
                            FiddlerApplication.Log.LogFormat("fiddler.network.streaming> Streaming of HTTP/1xx headers from #{0} to client failed: {1}", new object[] { this.m_session.id, exception.Message });
                        }
                    }
                    else
                    {
                        StringDictionary dictionary2;
                        (dictionary2 = this.m_session.oFlags)["x-fiddler-streaming"] = dictionary2["x-fiddler-streaming"] + "Eating a HTTP/" + this.m_inHeaders.HTTPResponseCode.ToString() + " message from the stream.";
                    }
                    this._deleteInformationalMessage();
                    return this.GetHeaders();
                }
            }
            return true;
        }

        private bool HeadersAvailable()
        {
            if (this.iEntityBodyOffset <= 0)
            {
                HTTPHeaderParseWarnings warnings;
                if (this.m_responseData == null)
                {
                    return false;
                }
                if (!Parser.FindEndOfHeaders(this.m_responseData.GetBuffer(), ref this._iBodySeekProgress, this.m_responseData.Length, out warnings))
                {
                    return false;
                }
                this.iEntityBodyOffset = this._iBodySeekProgress + 1;
                switch (warnings)
                {
                    case HTTPHeaderParseWarnings.EndedWithLFLF:
                        FiddlerApplication.HandleHTTPError(this.m_session, SessionFlags.ProtocolViolationInResponse, false, true, "The Server did not return properly formatted HTTP Headers. HTTP headers\nshould be terminated with CRLFCRLF. These were terminated with LFLF.");
                        break;

                    case HTTPHeaderParseWarnings.EndedWithLFCRLF:
                        FiddlerApplication.HandleHTTPError(this.m_session, SessionFlags.ProtocolViolationInResponse, false, true, "The Server did not return properly formatted HTTP Headers. HTTP headers\nshould be terminated with CRLFCRLF. These were terminated with LFCRLF.");
                        break;
                }
            }
            return true;
        }

        internal void Initialize(bool bAllocatePipeReadBuffer)
        {
            if (bAllocatePipeReadBuffer)
            {
                this.m_responseData = new PipeReadBuffer(false);
            }
            else
            {
                this.m_responseData = null;
            }
            this._lngLeakedOffset = this._iBodySeekProgress = this.iEntityBodyOffset = 0;
            this._lngLastChunkInfoOffset = -1;
            this.m_inHeaders = null;
            this._bLeakedHeaders = false;
            this.pipeServer = null;
            this._bWasForwarded = false;
            this.m_session.SetBitFlag(SessionFlags.ServerPipeReused, false);
        }

        private bool isResponseBodyComplete()
        {
            if (this.m_session.HTTPMethodIs("HEAD"))
            {
                return true;
            }
            if (this.m_session.HTTPMethodIs("CONNECT") && (this.m_inHeaders.HTTPResponseCode == 200))
            {
                return true;
            }
            if (((this.m_inHeaders.HTTPResponseCode == 0xcc) || (this.m_inHeaders.HTTPResponseCode == 0xcd)) || ((this.m_inHeaders.HTTPResponseCode == 0x130) || ((this.m_inHeaders.HTTPResponseCode > 0x63) && (this.m_inHeaders.HTTPResponseCode < 200))))
            {
                if (this.m_inHeaders.Exists("Content-Length") && ("0" != this.m_inHeaders["Content-Length"].Trim()))
                {
                    FiddlerApplication.HandleHTTPError(this.m_session, SessionFlags.ProtocolViolationInResponse, false, true, "This type of HTTP response MUST NOT contain a body, but a non-zero content-length was returned.");
                    return true;
                }
                return true;
            }
            if (this.m_inHeaders.ExistsAndEquals("Transfer-Encoding", "chunked"))
            {
                long num;
                if (this._lngLastChunkInfoOffset < this.iEntityBodyOffset)
                {
                    this._lngLastChunkInfoOffset = this.iEntityBodyOffset;
                }
                return Utilities.IsChunkedBodyComplete(this.m_session, this.m_responseData, this._lngLastChunkInfoOffset, out this._lngLastChunkInfoOffset, out num);
            }
            if (this.m_inHeaders.Exists("Content-Length"))
            {
                long num2;
                if (long.TryParse(this.m_inHeaders["Content-Length"], NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out num2) && (num2 >= 0))
                {
                    return (this.m_responseTotalDataCount >= (this.iEntityBodyOffset + num2));
                }
                FiddlerApplication.HandleHTTPError(this.m_session, SessionFlags.ProtocolViolationInResponse, true, true, "Content-Length response header is not a valid unsigned integer.\nContent-Length: " + this.m_inHeaders["Content-Length"]);
                return true;
            }
            if ((!this.m_inHeaders.ExistsAndEquals("Connection", "close") && !this.m_inHeaders.ExistsAndEquals("Proxy-Connection", "close")) && ((this.m_inHeaders.HTTPVersion == "HTTP/1.1") || this.m_inHeaders.ExistsAndContains("Connection", "Keep-Alive")))
            {
                FiddlerApplication.HandleHTTPError(this.m_session, SessionFlags.ProtocolViolationInResponse, true, true, "No Connection: close, no Content-Length. No way to tell if the response is complete.");
            }
            return false;
        }

        private bool LeakResponseBytes()
        {
            try
            {
                if (this.m_session.oRequest.pipeClient == null)
                {
                    return false;
                }
                if (!this._bLeakedHeaders)
                {
                    if (((0x191 == this.m_inHeaders.HTTPResponseCode) && this.m_inHeaders["WWW-Authenticate"].StartsWith("N", StringComparison.OrdinalIgnoreCase)) || ((0x197 == this.m_inHeaders.HTTPResponseCode) && this.m_inHeaders["Proxy-Authenticate"].StartsWith("N", StringComparison.OrdinalIgnoreCase)))
                    {
                        this.m_inHeaders["Proxy-Support"] = "Session-Based-Authentication";
                    }
                    this.m_session.Timers.ClientBeginResponse = DateTime.Now;
                    this._bLeakedHeaders = true;
                    this.m_session.oRequest.pipeClient.Send(this.m_inHeaders.ToByteArray(true, true));
                    this._lngLeakedOffset = this.iEntityBodyOffset;
                }
                this.m_session.oRequest.pipeClient.Send(this.m_responseData.GetBuffer(), (int) this._lngLeakedOffset, (int) (this.m_responseData.Length - this._lngLeakedOffset));
                this._lngLeakedOffset = this.m_responseData.Length;
                return true;
            }
            catch (Exception exception)
            {
                this.m_session.PoisonClientPipe();
                if (FiddlerApplication.Prefs.GetBoolPref("fiddler.network.streaming.abortifclientaborts", false))
                {
                    throw new OperationCanceledException("Leaking response to client failed", exception);
                }
                FiddlerApplication.Log.LogFormat("fiddler.network.streaming> Streaming of response #{0} to client failed: {1}. Leaking aborted.", new object[] { this.m_session.id, exception.Message });
                return false;
            }
        }

        private bool ParseResponseForHeaders()
        {
            if ((this.m_responseData != null) && (this.iEntityBodyOffset >= 4))
            {
                this.m_inHeaders = new HTTPResponseHeaders(CONFIG.oHeaderEncoding);
                byte[] bytes = this.m_responseData.GetBuffer();
                string str = CONFIG.oHeaderEncoding.GetString(bytes, 0, this.iEntityBodyOffset).Trim();
                if ((str == null) || (str.Length < 1))
                {
                    this.m_inHeaders = null;
                    return false;
                }
                string[] sHeaderLines = str.Replace("\r\n", "\n").Split(new char[] { '\n' });
                if (sHeaderLines.Length >= 1)
                {
                    int index = sHeaderLines[0].IndexOf(' ');
                    if (index > 0)
                    {
                        this.m_inHeaders.HTTPVersion = sHeaderLines[0].Substring(0, index).ToUpper();
                        sHeaderLines[0] = sHeaderLines[0].Substring(index + 1).Trim();
                        if (!this.m_inHeaders.HTTPVersion.StartsWith("HTTP/", StringComparison.OrdinalIgnoreCase))
                        {
                            if (!this.m_inHeaders.HTTPVersion.StartsWith("ICY", StringComparison.OrdinalIgnoreCase))
                            {
                                FiddlerApplication.HandleHTTPError(this.m_session, SessionFlags.ProtocolViolationInResponse, false, true, "Response does not start with HTTP. Data:\n\n\t" + sHeaderLines[0]);
                                return false;
                            }
                            this.m_session.bBufferResponse = false;
                            this.m_session.oFlags["log-drop-response-body"] = "ICY";
                        }
                        this.m_inHeaders.HTTPResponseStatus = sHeaderLines[0];
                        bool flag = false;
                        index = sHeaderLines[0].IndexOf(' ');
                        if (index > 0)
                        {
                            flag = int.TryParse(sHeaderLines[0].Substring(0, index).Trim(), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out this.m_inHeaders.HTTPResponseCode);
                        }
                        else
                        {
                            string s = sHeaderLines[0].Trim();
                            flag = int.TryParse(s, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out this.m_inHeaders.HTTPResponseCode);
                            if (!flag)
                            {
                                for (int i = 0; i < s.Length; i++)
                                {
                                    if (!char.IsDigit(s[i]))
                                    {
                                        flag = int.TryParse(s.Substring(0, i), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out this.m_inHeaders.HTTPResponseCode);
                                        if (flag)
                                        {
                                            FiddlerApplication.HandleHTTPError(this.m_session, SessionFlags.ProtocolViolationInResponse, false, false, "The response's status line was missing a space between ResponseCode and ResponseStatus. Data:\n\n\t" + s);
                                        }
                                        break;
                                    }
                                }
                            }
                        }
                        if (!flag)
                        {
                            FiddlerApplication.HandleHTTPError(this.m_session, SessionFlags.ProtocolViolationInResponse, false, true, "The response's status line did not contain a ResponseCode. Data:\n\n\t" + sHeaderLines[0]);
                            return false;
                        }
                        string sErrors = string.Empty;
                        if (!Parser.ParseNVPHeaders(this.m_inHeaders, sHeaderLines, 1, ref sErrors))
                        {
                            FiddlerApplication.HandleHTTPError(this.m_session, SessionFlags.ProtocolViolationInResponse, false, true, "Incorrectly formed response headers.\n" + sErrors);
                        }
                        return true;
                    }
                    FiddlerApplication.HandleHTTPError(this.m_session, SessionFlags.ProtocolViolationInResponse, false, true, "Cannot parse HTTP response; Status line contains no spaces. Data:\n\n\t" + sHeaderLines[0]);
                }
            }
            return false;
        }

        internal bool ReadResponse()
        {
            if (this.pipeServer == null)
            {
                if (this.m_session.isFTP && !this.m_session.isFlagSet(SessionFlags.SentToGateway))
                {
                    FTPGateway.MakeFTPRequest(this.m_session, ref this.m_responseData, out this.m_inHeaders);
                    return true;
                }
                return false;
            }
            int iMaxByteCount = 0;
            bool flag = false;
            bool flag2 = false;
            bool flag3 = false;
            bool flag4 = false;
            byte[] arrBuffer = new byte[_cbServerReadBuffer];
            do
            {
                try
                {
                    iMaxByteCount = this.pipeServer.Receive(arrBuffer);
                    if (0 == this.m_session.Timers.ServerBeginResponse.Ticks)
                    {
                        this.m_session.Timers.ServerBeginResponse = DateTime.Now;
                    }
                    if (iMaxByteCount <= 0)
                    {
                        flag = true;
                        if (CONFIG.bDebugSpew)
                        {
                            FiddlerApplication.DebugSpew(string.Format("READ FROM {0}: returned 0 signaling end-of-stream", this.pipeServer));
                        }
                    }
                    else
                    {
                        if (CONFIG.bDebugSpew)
                        {
                            FiddlerApplication.DebugSpew(string.Format("READ FROM {0}:\n{1}", this.pipeServer, Utilities.ByteArrayToHexView(arrBuffer, 0x20, iMaxByteCount)));
                        }
                        this.m_responseData.Write(arrBuffer, 0, iMaxByteCount);
                        this.m_responseTotalDataCount += iMaxByteCount;
                        if ((this.m_inHeaders == null) && this.GetHeaders())
                        {
                            this.m_session.Timers.FiddlerGotResponseHeaders = DateTime.Now;
                            if ((this.m_session.state == SessionStates.Aborted) && this.m_session.isAnyFlagSet(SessionFlags.ProtocolViolationInResponse))
                            {
                                return false;
                            }
                            FiddlerApplication.DoResponseHeadersAvailable(this.m_session);
                            string str = this.m_inHeaders["Content-Type"];
                            if ((str.StartsWith("text/event-stream", StringComparison.OrdinalIgnoreCase) || str.StartsWith("multipart/x-mixed-replace", StringComparison.OrdinalIgnoreCase)) && FiddlerApplication.Prefs.GetBoolPref("fiddler.network.streaming.AutoStreamByMIME", true))
                            {
                                this.m_session.bBufferResponse = false;
                            }
                            else if (CONFIG.bStreamAudioVideo && ((str.StartsWith("video/", StringComparison.OrdinalIgnoreCase) || str.StartsWith("audio/", StringComparison.OrdinalIgnoreCase)) || str.StartsWith("application/x-mms-framed", StringComparison.OrdinalIgnoreCase)))
                            {
                                this.m_session.bBufferResponse = false;
                            }
                            if (!this.m_session.bBufferResponse && this.m_session.HTTPMethodIs("CONNECT"))
                            {
                                this.m_session.bBufferResponse = true;
                            }
                            if (!this.m_session.bBufferResponse && (0x65 == this.m_inHeaders.HTTPResponseCode))
                            {
                                this.m_session.bBufferResponse = true;
                            }
                            if (!this.m_session.bBufferResponse && (this.m_session.oRequest.pipeClient == null))
                            {
                                this.m_session.bBufferResponse = true;
                            }
                            if ((!this.m_session.bBufferResponse && ((0x191 == this.m_inHeaders.HTTPResponseCode) || (0x197 == this.m_inHeaders.HTTPResponseCode))) && this.m_session.oFlags.ContainsKey("x-AutoAuth"))
                            {
                                this.m_session.bBufferResponse = true;
                            }
                            this.m_session.ExecuteBasicResponseManipulationsUsingHeadersOnly();
                            this.m_session.SetBitFlag(SessionFlags.ResponseStreamed, !this.m_session.bBufferResponse);
                            if (!this.m_session.bBufferResponse)
                            {
                                if (this.m_session.oFlags.ContainsKey("response-trickle-delay"))
                                {
                                    int num2 = int.Parse(this.m_session.oFlags["response-trickle-delay"]);
                                    this.m_session.oRequest.pipeClient.TransmitDelay = num2;
                                }
                                if (this.m_session.oFlags.ContainsKey("log-drop-response-body") || FiddlerApplication.Prefs.GetBoolPref("fiddler.network.streaming.ForgetStreamedData", false))
                                {
                                    flag3 = true;
                                }
                            }
                        }
                        if ((this.m_inHeaders != null) && this.m_session.isFlagSet(SessionFlags.ResponseStreamed))
                        {
                            if (!flag4 && !this.LeakResponseBytes())
                            {
                                flag4 = true;
                            }
                            if (flag3)
                            {
                                this.m_session.SetBitFlag(SessionFlags.ResponseBodyDropped, true);
                                if (this._lngLastChunkInfoOffset > -1)
                                {
                                    this.ReleaseStreamedChunkedData();
                                }
                                else if (this.m_inHeaders.ExistsAndContains("Transfer-Encoding", "chunked"))
                                {
                                    this.ReleaseStreamedChunkedData();
                                }
                                else
                                {
                                    this.ReleaseStreamedData();
                                }
                            }
                        }
                    }
                }
                catch (Exception exception)
                {
                    flag2 = true;
                    if ((exception is SocketException) && (((SocketException) exception).ErrorCode == 0x274c))
                    {
                        this.m_session["X-ServerPipeError"] = "Timed out while reading response.";
                    }
                    else if (exception is OperationCanceledException)
                    {
                        this.m_session.state = SessionStates.Aborted;
                        FiddlerApplication.Log.LogFormat("fiddler.network.readresponse.failure> Session #{0} was aborted {1}", new object[] { this.m_session.id, Utilities.DescribeException(exception) });
                    }
                    else if (exception is OutOfMemoryException)
                    {
                        FiddlerApplication.ReportException(exception);
                        this.m_session.state = SessionStates.Aborted;
                        FiddlerApplication.Log.LogFormat("fiddler.network.readresponse.failure> Session #{0} Out of Memory", new object[] { this.m_session.id });
                    }
                    else
                    {
                        FiddlerApplication.Log.LogFormat("fiddler.network.readresponse.failure> Session #{0} raised exception {1}", new object[] { this.m_session.id, Utilities.DescribeException(exception) });
                    }
                }
            }
            while ((!flag && !flag2) && ((this.m_inHeaders == null) || !this.isResponseBodyComplete()));
            this.m_session.Timers.ServerDoneResponse = DateTime.Now;
            if (this.m_session.isFlagSet(SessionFlags.ResponseStreamed))
            {
                this.m_session.Timers.ClientDoneResponse = this.m_session.Timers.ServerDoneResponse;
            }
            if ((this.m_responseTotalDataCount == 0) && (this.m_inHeaders == null))
            {
                flag2 = true;
            }
            arrBuffer = null;
            if (flag2)
            {
                this.m_responseData.Dispose();
                this.m_responseData = null;
                return false;
            }
            if (this.m_inHeaders == null)
            {
                FiddlerApplication.HandleHTTPError(this.m_session, SessionFlags.ProtocolViolationInResponse, true, true, "The Server did not return properly formatted HTTP Headers. Maybe missing altogether (e.g. HTTP/0.9), maybe only \\r\\r instead of \\r\\n\\r\\n?\n");
                this.m_session.SetBitFlag(SessionFlags.ResponseStreamed, false);
                this.m_inHeaders = new HTTPResponseHeaders(CONFIG.oHeaderEncoding);
                this.m_inHeaders.HTTPVersion = "HTTP/1.0";
                this.m_inHeaders.HTTPResponseCode = 200;
                this.m_inHeaders.HTTPResponseStatus = "200 This buggy server did not return headers";
                this.iEntityBodyOffset = 0;
                return true;
            }
            return true;
        }

        internal bool ReadResponseFromFile(string sFilename)
        {
            byte[] buffer;
            if (!System.IO.File.Exists(sFilename))
            {
                this._ReturnFileReadError("Fiddler - The requested file was not found.", "Fiddler - The file '" + sFilename + "' was not found.");
                return false;
            }
            try
            {
                buffer = System.IO.File.ReadAllBytes(sFilename);
            }
            catch (Exception exception)
            {
                this._ReturnFileReadError("Fiddler - The requested file could not be read.", "Fiddler - The requested file could not be read. " + Utilities.DescribeException(exception));
                return false;
            }
            this.Initialize(true);
            int length = buffer.Length;
            int index = 0;
            bool flag = (((buffer.Length > 3) && (buffer[0] == 0xef)) && (buffer[1] == 0xbb)) && (buffer[2] == 0xbf);
            if (flag)
            {
                index = 3;
                length -= 3;
            }
            bool flag2 = ((((buffer.Length > (5 + index)) && (buffer[index] == 0x48)) && ((buffer[index + 1] == 0x54) && (buffer[index + 2] == 0x54))) && (buffer[index + 3] == 80)) && (buffer[index + 4] == 0x2f);
            if (flag && !flag2)
            {
                length += 3;
                index = 0;
            }
            this.m_responseData.Capacity = length;
            this.m_responseData.Write(buffer, index, length);
            if ((flag2 && this.HeadersAvailable()) && this.ParseResponseForHeaders())
            {
                this.m_session.responseBodyBytes = this.TakeEntity();
            }
            else
            {
                this.Initialize(false);
                this.m_inHeaders = new HTTPResponseHeaders(CONFIG.oHeaderEncoding);
                this.m_inHeaders.HTTPResponseCode = 200;
                this.m_inHeaders.HTTPResponseStatus = "200 OK with automatic headers";
                this.m_inHeaders["Date"] = DateTime.Now.ToUniversalTime().ToString("r");
                this.m_inHeaders["Content-Length"] = buffer.LongLength.ToString();
                this.m_inHeaders["Cache-Control"] = "max-age=0, must-revalidate";
                string str = Utilities.ContentTypeForFileExtension(Path.GetExtension(sFilename));
                if (str != null)
                {
                    this.m_inHeaders["Content-Type"] = str;
                }
                this.m_session.responseBodyBytes = buffer;
            }
            return true;
        }

        internal void releaseServerPipe()
        {
            if (this.pipeServer != null)
            {
                if (((this.headers.ExistsAndEquals("Connection", "close") || this.headers.ExistsAndEquals("Proxy-Connection", "close")) || ((this.headers.HTTPVersion != "HTTP/1.1") && !this.headers.ExistsAndContains("Connection", "Keep-Alive"))) || !this.pipeServer.Connected)
                {
                    this.pipeServer.ReusePolicy = PipeReusePolicy.NoReuse;
                }
                this._detachServerPipe();
            }
        }

        private void ReleaseStreamedChunkedData()
        {
            long num;
            if (this.iEntityBodyOffset > this._lngLastChunkInfoOffset)
            {
                this._lngLastChunkInfoOffset = this.iEntityBodyOffset;
            }
            Utilities.IsChunkedBodyComplete(this.m_session, this.m_responseData, this._lngLastChunkInfoOffset, out this._lngLastChunkInfoOffset, out num);
            int iDefaultCapacity = (int) (this.m_responseData.Length - this._lngLastChunkInfoOffset);
            PipeReadBuffer buffer = new PipeReadBuffer(iDefaultCapacity);
            buffer.Write(this.m_responseData.GetBuffer(), (int) this._lngLastChunkInfoOffset, iDefaultCapacity);
            this.m_responseData = buffer;
            this._lngLeakedOffset = iDefaultCapacity;
            this._lngLastChunkInfoOffset = 0;
            this.iEntityBodyOffset = 0;
        }

        private void ReleaseStreamedData()
        {
            this.m_responseData = new PipeReadBuffer(false);
            this._lngLeakedOffset = 0;
            if (this.iEntityBodyOffset > 0)
            {
                this.m_responseTotalDataCount -= this.iEntityBodyOffset;
                this.iEntityBodyOffset = 0;
            }
        }

        internal bool ResendRequest()
        {
            bool b = this.pipeServer != null;
            if (!this.ConnectToHost())
            {
                FiddlerApplication.DebugSpew("ConnectToHost returned null. Bailing...");
                this.m_session.SetBitFlag(SessionFlags.ServerPipeReused, b);
                return false;
            }
            try
            {
                if (this.m_session.isFTP && !this.m_session.isFlagSet(SessionFlags.SentToGateway))
                {
                    return true;
                }
                this.pipeServer.IncrementUse(this.m_session.id);
                this.pipeServer.setTimeouts();
                this.m_session.Timers.ServerConnected = this.pipeServer.dtConnected;
                this._bWasForwarded = this.pipeServer.isConnectedToGateway;
                this.m_session.SetBitFlag(SessionFlags.ServerPipeReused, this.pipeServer.iUseCount > 1);
                this.m_session.SetBitFlag(SessionFlags.SentToGateway, this._bWasForwarded);
                if (!this._bWasForwarded && !this.m_session.isHTTPS)
                {
                    this.m_session.oRequest.headers.RenameHeaderItems("Proxy-Connection", "Connection");
                }
                if (!this.pipeServer.isAuthenticated)
                {
                    string str = this.m_session.oRequest.headers["Authorization"];
                    if ((str != null) && str.StartsWith("N"))
                    {
                        this.pipeServer.MarkAsAuthenticated(this.m_session.LocalProcessID);
                    }
                }
                this.m_session.Timers.FiddlerBeginRequest = DateTime.Now;
                if (this.m_session.oFlags.ContainsKey("request-trickle-delay"))
                {
                    int num = int.Parse(this.m_session.oFlags["request-trickle-delay"]);
                    this.pipeServer.TransmitDelay = num;
                }
                if (this._bWasForwarded || !this.m_session.HTTPMethodIs("CONNECT"))
                {
                    this.pipeServer.Send(this.m_session.oRequest.headers.ToByteArray(true, true, this._bWasForwarded && !this.m_session.isHTTPS));
                    if ((this.m_session.requestBodyBytes != null) && (this.m_session.requestBodyBytes.Length > 0))
                    {
                        if (this.m_session.oFlags.ContainsKey("request-body-delay"))
                        {
                            Thread.Sleep(int.Parse(this.m_session.oFlags["request-body-delay"]));
                        }
                        this.pipeServer.Send(this.m_session.requestBodyBytes);
                    }
                }
            }
            catch (Exception exception)
            {
                if (this.bServerSocketReused && (this.m_session.state != SessionStates.Aborted))
                {
                    this.pipeServer = null;
                    return this.ResendRequest();
                }
                FiddlerApplication.DebugSpew("ResendRequest() failed: " + Utilities.DescribeException(exception));
                this.m_session.oRequest.FailSession(0x1f8, "Fiddler - Send Failure", "[Fiddler] ResendRequest() failed: " + Utilities.DescribeException(exception));
                return false;
            }
            this.m_session.oFlags["x-EgressPort"] = this.pipeServer.LocalPort.ToString();
            if (this.m_session.oFlags.ContainsKey("log-drop-request-body"))
            {
                this.m_session.oFlags["x-RequestBodyLength"] = (this.m_session.requestBodyBytes != null) ? this.m_session.requestBodyBytes.Length.ToString() : "0";
                this.m_session.requestBodyBytes = new byte[0];
            }
            return true;
        }

        private static bool SendHTTPCONNECTToGateway(Socket oGWSocket, string sHost, int iPort, HTTPRequestHeaders oRH)
        {
            string str = oRH["User-Agent"];
            string str2 = oRH["Proxy-Authorization"];
            string s = string.Format("CONNECT {0}:{1} HTTP/1.1\r\n{2}{3}Connection: close\r\n\r\n", new object[] { sHost, iPort, string.IsNullOrEmpty(str) ? string.Empty : string.Format("User-Agent: {0}\r\n", str), string.IsNullOrEmpty(str2) ? string.Empty : string.Format("Proxy-Authorization: {0}\r\n", str2) });
            oGWSocket.Send(Encoding.ASCII.GetBytes(s));
            byte[] buffer = new byte[0x2000];
            int num = oGWSocket.Receive(buffer);
            if ((num > 12) && Utilities.isHTTP200Array(buffer))
            {
                return true;
            }
            if ((num > 12) && Utilities.isHTTP407Array(buffer))
            {
                FiddlerApplication.Log.LogFormat("fiddler.network.connect2> Upstream gateway demanded proxy authentication, which is not supported in this scenario. {0}", new object[] { Encoding.UTF8.GetString(buffer, 0, Math.Min(num, 0x100)) });
                return false;
            }
            FiddlerApplication.Log.LogFormat("fiddler.network.connect2> Unexpected response from upstream gateway {0}", new object[] { Encoding.UTF8.GetString(buffer, 0, Math.Min(num, 0x100)) });
            return false;
        }

        private static bool SIDsMatch(int iPID, string sIDSession, string sIDPipe)
        {
            return (string.Equals(sIDSession, sIDPipe, StringComparison.Ordinal) || ((iPID != 0) && string.Equals(string.Format("PID{0}*{1}", iPID, sIDSession), sIDPipe, StringComparison.Ordinal)));
        }

        internal byte[] TakeEntity()
        {
            byte[] bytes;
            try
            {
                bytes = new byte[this.m_responseData.Length - this.iEntityBodyOffset];
                this.m_responseData.Position = this.iEntityBodyOffset;
                this.m_responseData.Read(bytes, 0, bytes.Length);
            }
            catch (OutOfMemoryException exception)
            {
                FiddlerApplication.ReportException(exception, "HTTP Response Too Large");
                bytes = Encoding.ASCII.GetBytes("Fiddler: Out of memory");
                this.m_session.PoisonServerPipe();
            }
            this.FreeResponseDataBuffer();
            return bytes;
        }

        internal long _PeekDownloadProgress
        {
            get
            {
                if (this.m_responseData != null)
                {
                    return this.m_responseTotalDataCount;
                }
                return -1;
            }
        }

        public bool bServerSocketReused
        {
            get
            {
                return this.m_session.isFlagSet(SessionFlags.ServerPipeReused);
            }
        }

        public bool bWasForwarded
        {
            get
            {
                return this._bWasForwarded;
            }
        }

        public HTTPResponseHeaders headers
        {
            get
            {
                return this.m_inHeaders;
            }
            set
            {
                if (value != null)
                {
                    this.m_inHeaders = value;
                }
            }
        }

        public string this[string sHeader]
        {
            get
            {
                if (this.m_inHeaders != null)
                {
                    return this.m_inHeaders[sHeader];
                }
                return string.Empty;
            }
            set
            {
                if (this.m_inHeaders == null)
                {
                    throw new InvalidDataException("Response Headers object does not exist");
                }
                this.m_inHeaders[sHeader] = value;
            }
        }

        public int iTTFB
        {
            get
            {
                TimeSpan span = (TimeSpan) (this.m_session.Timers.ServerBeginResponse - this.m_session.Timers.FiddlerBeginRequest);
                int totalMilliseconds = (int) span.TotalMilliseconds;
                if (totalMilliseconds <= 0)
                {
                    return 0;
                }
                return totalMilliseconds;
            }
        }

        public int iTTLB
        {
            get
            {
                TimeSpan span = (TimeSpan) (this.m_session.Timers.ServerDoneResponse - this.m_session.Timers.FiddlerBeginRequest);
                int totalMilliseconds = (int) span.TotalMilliseconds;
                if (totalMilliseconds <= 0)
                {
                    return 0;
                }
                return totalMilliseconds;
            }
        }

        public string MIMEType
        {
            get
            {
                if (this.headers == null)
                {
                    return string.Empty;
                }
                string sString = this.headers["Content-Type"];
                if (sString.Length > 0)
                {
                    sString = Utilities.TrimAfter(sString, ';').Trim();
                }
                return sString;
            }
        }
    }
}

